package com.lenovo.sdc.framework.common.base;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

/**
 * 标准的rest方法列表
 * <pre>
 * /userinfo                => index()  
 * /userinfo/new            => _new()  注意: 不使用/userinfo/add => add()的原因是ad会被一些浏览器当做广告URL拦截
 * /userinfo/{id}           => show()  
 * /userinfo/{id}/edit      => edit()  
 * /userinfo        POST    => create()  
 * /userinfo/{id}   PUT    update => ()  
 * /userinfo/{id}   DELETE  => delete()  
 * /userinfo        DELETE  => batchDelete()  
 * </pre>
 * 
 */
public class BaseRestSpringController {
    protected Log log = LogFactory.getLog(this.getClass());
    
    @Autowired
    private Validator validator;
    
    @Autowired
    @Qualifier("messageSource")
    private MessageSource messageSource;
    
    /**
     * Http Request parameter validator
     * 
     * @return
     */
    protected Validator getValidator() {
        return validator;
    }

    /**
     * can replace spring default validator
     * 
     * @param validator
     */
    protected void setValidator(Validator validator) {
        this.validator = validator;
    }
    
    protected MessageSource getMessageSource() {
        return messageSource;
    }

    protected void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    /**
     * apply for validator to check input parameter according to jsp303 annotation
     * if found error returned map will contain field name and its error information
     * 
     * @param obj
     * @return
     */
    protected <T> Map<String, String> hasError(T obj) {
        Set<ConstraintViolation<T>> failures = validator.validate(obj);
        Map<String, String> failureMessages = new HashMap<String, String>();
        for (ConstraintViolation<?> failure : failures) {
            failureMessages.put(failure.getPropertyPath().toString(), failure.getMessage());
        }
        return failureMessages;
    }
    
    /**
     * return session related with current request thread. 
     * my target is to avoid define input parameter in interface of controller
     * @return
     */
    protected HttpSession getCurrentSession() {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        if (attr == null)
            throw new IllegalArgumentException("miss session, need to login again");
        
        return attr.getRequest().getSession(false);
    }
    
    /**
     * return i18n string base on current locale setting of session
     * 
     * @param code message code defined in i18n file
     * @param params values to replace place-holder in message
     * @return
     */
    public String getLocalMessage(String code, Object[] params) {
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        if (attr == null)
            return messageSource.getMessage(code, params, Locale.getDefault());

        return messageSource.getMessage(code, params, attr.getRequest().getLocale());
    }
    
    /**
     * process any exception thrown by controller interface.
     * default implement is log error only, hope sub-class to implement himself logic and add error page
     * 
     * @param ex
     * @param request
     * @param response
     * @return
     */
    @ExceptionHandler(Exception.class)
    protected ModelAndView handleException(Exception exp, HttpServletRequest request, HttpServletResponse response) {
        log.warn("controller interface exception:", exp);
        response.setStatus(500);
        return null;
    }
}
